﻿using System;
using System.Collections;
using System.Collections.Generic;
using Me.Prettyprint.Cassandra.Connection;
using Me.Prettyprint.Cassandra.Serializers;
using Me.Prettyprint.Cassandra.Service;
using Me.Prettyprint.Cassandra.Utils;
using Me.Prettyprint.Hector.Api;
using Me.Prettyprint.Hector.Api.Beans;
using Me.Prettyprint.Hector.Api.Query;
using Org.Apache.Cassandra.Thrift;

namespace Me.Prettyprint.Cassandra.Model
{
    /// <summary>
    /// Default implementation of HCounterColumn has a name, value and
    /// name serializer.
    /// </summary>
    /// <typeparam name="N"></typeparam>
    public class HCounterColumnImpl<N> : HCounterColumn<N>
    {
        #region Constructors
        public HCounterColumnImpl(N name, long value, Serializer<N> nameSerializer) : this(nameSerializer)
        {
            if (name == null || value == null)
            {
                throw new NullReferenceException("Name and Value cannot be null");
            }
            CounterColumn = new CounterColumn();
            CounterColumn.Name = nameSerializer.ToBytes(name);
            CounterColumn.Value = value;
            CounterColumn.__isset.name = true;
            CounterColumn.__isset.value = true;
        }
        public HCounterColumnImpl(CounterColumn thriftCounterColumn, Serializer<N> nameSerializer) : this(nameSerializer)
        {
            if (thriftCounterColumn == null)
            {
                throw new NullReferenceException("CounterColumn cannot be null");
            }
            CounterColumn = thriftCounterColumn;
        }
        public HCounterColumnImpl(Serializer<N> nameSerializer)
        {
            if (nameSerializer == null)
            {
                throw new NullReferenceException("Name Serializer cannot be null");
            }
            NameSerializer = nameSerializer;
            CounterColumn = new CounterColumn();
        }
        public HCounterColumnImpl(N name, long value)
            : this(name, value, SerializerTypeInferer.GetSerializer<N>(name))
        {
        }
        #endregion Constructors
        protected CounterColumn CounterColumn
        {
            get;
            set;
        }
        public Serializer<N> NameSerializer
        {
            get;
            set;
        }
        public int Ttl
        {
            get
            {
                return int.MaxValue;
            }
        }
        public N GetName() 
        {
            return CounterColumn.Name != null ? NameSerializer.FromBytes(CounterColumn.Name) : default(N);
        }
        public long GetValue() 
        {
            return CounterColumn.Value;
        }
        public CounterColumn ToThrift()
        {
            return CounterColumn;
        }
        public HCounterColumn<N> SetName(N name)
        {
            if (name == null)
            {
                throw new NullReferenceException("Name cannot be null");
            }
            CounterColumn.Name = NameSerializer.ToBytes(name);
            return this;
        }
        public HCounterColumn<N> SetValue(long value)
        {
            if (value == null)
            {
                throw new NullReferenceException("Value cannot be null");
            }
            CounterColumn.Value = value;
            return this;
        }
        public HCounterColumn<N> SetTtl(int ttl) 
        {
            //CounterColumn.setTtl(ttl);
            // TODO (patricioe) Pending on Cassandra trunk
            return this;
        }
        public HCounterColumn<N> FromThrift(CounterColumn c)
        {
            if (c == null)
            {
                throw new NullReferenceException("CounterColumn cannot be null");
            }
            CounterColumn = c;
            return this;
        }
        public byte[] NameBytes
        {
            get
            {
                return CounterColumn.Name != null ? CounterColumn.Name : null;
            }
        }
        public HCounterColumn<N> Clear()
        {
            CounterColumn.Value = 0; // TODO (patricioe) Is this ok?
            return this;
        }
        public HCounterColumn<N> Apply(long value, int ttl)
        {
            SetValue(value);
            //counterColumn.setTtl(ttl);
            return this;
        }
        public HCounterColumn<N> Apply(CounterColumn c)
        {
            CounterColumn = c;
            return this;
        }
        public override string ToString()
        {
            return string.Format("HCounterColumn({0}={1})",GetName(), GetValue());
        }
        public override int GetHashCode()
        {
            int hcode = 0;
            if (CounterColumn != null && CounterColumn.Name != null)
            {
                hcode += CounterColumn.Name.GetHashCode();
                if (CounterColumn.Value != null)
                {
                    hcode += CounterColumn.Value.GetHashCode();
                }
            }
            return hcode;
        }
        public override bool Equals(object obj)
        {
            if (obj == null)
            {
                return false;
            }
            if (obj == this)
            {
                return true;
            }
            if (obj.GetType() != GetType())
            {
                return false;
            }
            HCounterColumnImpl<N> other = (HCounterColumnImpl<N>)obj;
            if (GetName().Equals(other.GetName()) && GetValue().Equals(other.GetValue()))
            {
                return true;
            }
            return false;
        }
    }
}
